﻿using BIStudio.Framework.Utils;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace BIStudio.Framework.MQ
{
    /// <summary>
    /// 订阅本地消息
    /// </summary>
    internal class LocalMessageDispatcher : MessageDispatcher, IMessageDispatcher
    {
        public LocalMessageDispatcher()
        {
            CFConfig.Default.ScanTypes(handlerType =>
            {
                //过滤接口（获取一个值，通过该值指示 System.Type 是否为接口（即不是类或值类型））
                if (handlerType.IsInterface)
                    return;
                //循环:当在派生类中重写时，获取由当前 System.Type 实现或继承的所有接口
                foreach (Type interfaceType in handlerType.ImplementedInterfaces)
                {
                    //获取一个值，该值指示当前类型是是泛型类型 &&当前类型符合命令或者事件消息对应的接口 
                    if (interfaceType.IsGenericType && genericHandlerType == interfaceType.GetGenericTypeDefinition())
                    {
                        //通过反射获取命令或者事件Handler具体类:比如(new ExpireAreaChennelEventHandler())
                        var handler = Activator.CreateInstance(handlerType);
                        //命令或者事件类型：比如（IEventHandler<ExpireAreaChennelEvent>泛型类型的类型实参：ExpireAreaChennelEvent）
                        var messageType = interfaceType.GetGenericArguments()[0];
                        //通过反射获取命令或者事件具体类:比如(new ExpireAreaChennelEvent())
                        var message = (IMessage)Activator.CreateInstance(messageType);
                        //得到命令或者事件具体类的Handle方法
                        var method = handlerType.GetMethod("Handle", BindingFlags.Instance | BindingFlags.Public |
                            BindingFlags.InvokeMethod | BindingFlags.DeclaredOnly, Type.DefaultBinder, new Type[] { messageType }, null);
                        //订阅消息
                        this.Subscribe(message.TypeName, new MessageListener
                        {
                            Target = messageType,
                            Handler = arg => method.Invoke(handler, new object[] { arg }),
                        });
                    }
                }
            });
        }
    }
}
